package com.travelcloud.framework.utils;

import com.alibaba.fastjson.JSON;
import org.springframework.beans.BeanUtils;
import org.springframework.cglib.beans.BeanMap;

import java.util.*;
import java.util.function.Supplier;

/**
 * 转换对象工具
 *
 * @author Zee
 * @date 2020年6月19日
 */
public class MyBeanUtils extends BeanUtils {
    /**
     * 拷贝bean属性
     *
     * @param source 源对象
     * @param target 目标对像
     * @param <S>    源对象类型
     * @param <T>    目标对象类型
     */
    public static <S, T> void copyBeanProperties(S source, T target) {
        copyBeanProperties(source, target, null);
    }

    /**
     * 拷贝bean属性
     * @param source   源对象
     * @param target   目标对像
     * @param <S>      源对象类型
     * @param <T>      目标对象类型
     * @param callBack 回调
     */
    public static <S, T> void copyBeanProperties(S source, T target, ConvertCallBack<S, T> callBack) {
        copyProperties(source, target);
        if (Objects.nonNull(callBack)) {
            callBack.callBack(source, target);
        }

    }

    /**
     * 转换对象
     *
     * @param source         源对象
     * @param targetSupplier 目标对象供应方
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象
     */
    public static <S, T> T copyToBean(S source, Supplier<T> targetSupplier) {
        return copyToBean(source, targetSupplier, null);
    }

    /**
     * 转换对象带回调
     *
     * @param source         源对象
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象
     */
    public static <S, T> T copyToBean(S source, Supplier<T> targetSupplier, ConvertCallBack<S, T> callBack) {
        if (Objects.isNull(source) || Objects.isNull(targetSupplier)) {
            return null;
        }
        T target = targetSupplier.get();
        copyProperties(source, target);
        if (Objects.nonNull(callBack)) {
            callBack.callBack(source, target);
        }
        return target;
    }

    /**
     * 转换list对象
     *
     * @param sources        源对象list
     * @param targetSupplier 目标对象供应方
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象list
     */
    public static <S, T> List<T> copyToList(List<S> sources, Supplier<T> targetSupplier) {
        return copyToList(sources, targetSupplier, null);
    }

    /**
     * 转换list对象带回调
     *
     * @param sources        源对象list
     * @param targetSupplier 目标对象供应方
     * @param callBack       回调方法
     * @param <S>            源对象类型
     * @param <T>            目标对象类型
     * @return 目标对象list
     */
    public static <S, T> List<T> copyToList(List<S> sources, Supplier<T> targetSupplier, ConvertListCallBack<S, T> callBack) {
        if (Objects.isNull(sources) || Objects.isNull(targetSupplier)) {
            return null;
        }
        List<T> list = new ArrayList<>(sources.size());
        for (int index = 0; index < sources.size(); index++) {
            S source = sources.get(index);
            T target = targetSupplier.get();
            copyProperties(source, target);
            if (Objects.nonNull(callBack)) {
                callBack.callBack(index, source, target);
            }
            list.add(target);
        }
        return list;
    }

    /**
     * 将Bean对象装换为map
     *
     * @param bean bean对像
     * @return 返回Map
     */
    public static <T> Map<String, Object> beanToMap(T bean) {
        Map<String, Object> map = new HashMap<>(16);
        if (Objects.nonNull(bean)) {
            BeanMap beanMap = BeanMap.create(bean);
            for (Object key : beanMap.keySet()) {
                map.put(String.valueOf(key), beanMap.get(key));
            }
        }
        return map;
    }

    /**
     * @param map            map对像
     * @param targetSupplier 目标对像
     * @param <T>            目录对像
     * @return Bean
     */
    public static <T> T mapToBean(Map<?, ?> map, Supplier<T> targetSupplier) {
        return mapToBean(map, targetSupplier, null);
    }

    /**
     * @param map            map对像
     * @param targetSupplier 目标对像
     * @param <T>            目录对像
     * @param callBack       回调方法
     * @return Bean
     */
    public static <T> T mapToBean(Map<?, ?> map, Supplier<T> targetSupplier, ConvertMapCallBack<T> callBack) {
        T target = targetSupplier.get();
        BeanMap beanMap = BeanMap.create(target);
        beanMap.putAll(map);
        if (Objects.nonNull(callBack)) {
            callBack.callBack(target);
        }
        return target;
    }

    /**
     * Object转成JSON数据
     *
     * @param object 对像
     * @return json字符串
     */
    public static String objectToJson(Object object) {
        if (object instanceof Integer || object instanceof Long || object instanceof Float ||
                object instanceof Double || object instanceof Boolean || object instanceof String) {
            return String.valueOf(object);
        }
        return JSON.toJSONString(object);
    }

    /**
     * JSON数据，转成Object
     *
     * @param json  json字符串
     * @param clazz 转换实体
     * @param <T>   转换实体
     * @return 转换实体
     */
    public static <T> T jsonToObject(String json, Class<T> clazz) {
        return JSON.parseObject(json, clazz);
    }

    @FunctionalInterface
    public interface ConvertMapCallBack<T> {
        /**
         * 回调方法
         *
         * @param t target
         */
        void callBack(T t);
    }

    @FunctionalInterface
    public interface ConvertCallBack<S, T> {
        /**
         * 回调方法
         *
         * @param s source
         * @param t target
         */
        void callBack(S s, T t);
    }

    @FunctionalInterface
    public interface ConvertListCallBack<S, T> {
        /**
         * 回调方法
         *
         * @param s     source
         * @param t     target
         * @param index index
         */
        void callBack(Integer index, S s, T t);
    }
}